// shm_lc_map.h
#pragma once
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <atomic>
#include <cstdint>
#include <string>
#include <chrono>
#include <cstdio>

struct alignas(64) ShmLcMap {
    // seqlock: 偶数=稳定，奇数=写入中
    std::atomic<uint64_t> seq;
    // 锚点：R_anchor = 原始单调时钟(ns)，L_anchor = 逻辑时钟(ns)
    uint64_t R_anchor_ns;
    int64_t  L_anchor_ns;
    double   s_ns_per_ns;       // 当前追赶斜率
    uint32_t version;           // 方便将来升级
    uint32_t _pad{0};
};

class ShmLcPublisher {
public:
    explicit ShmLcPublisher(const std::string& name = "/lc_map_v1")
    : name_(name) { open_or_create(true); }

    ~ShmLcPublisher() { close_unmap(); }

    // 在“提交/重定锚”时调用：把三个量写进去
    inline void publish(uint64_t R_anchor_ns,
                        int64_t  L_anchor_ns,
                        double   s_ns_per_ns,
                        uint32_t version = 1) noexcept {
        if (!ptr_) return;
        ptr_->seq.fetch_add(1, std::memory_order_acq_rel); // -> odd
        ptr_->R_anchor_ns = R_anchor_ns;
        ptr_->L_anchor_ns = L_anchor_ns;
        ptr_->s_ns_per_ns = s_ns_per_ns;
        ptr_->version     = version;
        ptr_->seq.fetch_add(1, std::memory_order_acq_rel); // -> even
    }

    ShmLcMap* raw() noexcept { return ptr_; }

private:
    std::string name_;
    int fd_{-1};
    ShmLcMap* ptr_{nullptr};
    static constexpr size_t kSize = sizeof(ShmLcMap);

    void open_or_create(bool create) {
        int flags = O_RDWR; if (create) flags |= O_CREAT;
        fd_ = shm_open(name_.c_str(), flags, 0660);
        if (fd_ < 0) { perror("shm_open"); return; }
        if (create) {
            if (ftruncate(fd_, kSize) != 0) { perror("ftruncate"); }
        }
        void* p = mmap(nullptr, kSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd_, 0);
        if (p == MAP_FAILED) { perror("mmap"); close(fd_); fd_=-1; return; }
        ptr_ = reinterpret_cast<ShmLcMap*>(p);
        // 初始值（幂等）
        if (ptr_->seq.load(std::memory_order_relaxed) == 0) {
            ptr_->R_anchor_ns = 0;
            ptr_->L_anchor_ns = 0;
            ptr_->s_ns_per_ns = 1.0;
            ptr_->version     = 1;
        }
    }
    void close_unmap() {
        if (ptr_) { munmap((void*)ptr_, kSize); ptr_ = nullptr; }
        if (fd_>=0) { close(fd_); fd_ = -1; }
    }
};

class ShmLcReader {
public:
    explicit ShmLcReader(const std::string& name = "/lc_map_v1")
    : name_(name) { open_map(); }
    ~ShmLcReader() { close_unmap(); }

    // 读快照（拿到 R_anchor/L_anchor/s）
    bool snapshot(ShmLcMap& out) const noexcept {
        if (!ptr_) return false;
        while (true) {
            uint64_t r1 = ptr_->seq.load(std::memory_order_acquire);
            if (r1 & 1) continue;
            out.R_anchor_ns = ptr_->R_anchor_ns;
            out.L_anchor_ns = ptr_->L_anchor_ns;
            out.s_ns_per_ns = ptr_->s_ns_per_ns;
            out.version     = ptr_->version;
            uint64_t r2 = ptr_->seq.load(std::memory_order_acquire);
            if (r1 == r2 && !(r2 & 1)) return true;
        }
    }

    // 给读者一个现成函数：传入当前原始单调时间，返回逻辑时间
    int64_t logical_now_from_raw(uint64_t R_now_ns) const noexcept {
        ShmLcMap snap{};
        if (!snapshot(snap)) return 0;
        // L = L_anchor + s*(R_now - R_anchor)
        long double delta = (long double)R_now_ns - (long double)snap.R_anchor_ns;
        long double L = (long double)snap.L_anchor_ns + (long double)snap.s_ns_per_ns * delta;
        return (int64_t)L;
    }

private:
    std::string name_;
    int fd_{-1};
    ShmLcMap* ptr_{nullptr};
    static constexpr size_t kSize = sizeof(ShmLcMap);
    void open_map() {
        fd_ = shm_open(name_.c_str(), O_RDWR, 0660);
        if (fd_ < 0) { perror("shm_open"); return; }
        void* p = mmap(nullptr, kSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd_, 0);
        if (p == MAP_FAILED) { perror("mmap"); close(fd_); fd_=-1; return; }
        ptr_ = reinterpret_cast<ShmLcMap*>(p);
    }
    void close_unmap() {
        if (ptr_) { munmap((void*)ptr_, kSize); ptr_ = nullptr; }
        if (fd_>=0) { close(fd_); fd_ = -1; }
    }
};
